/*
 * SecuentialBlock.h
 *
 */

#ifndef SECUENTIALBLOCK_H_
#define SECUENTIALBLOCK_H_

#include <iterator>
#include <vector>
#include "../IEvaluator.h"
#include "../BlockPersistor.h"
#include "../../utils/Utils.h"
#include "../../log/Logger.h"

template <class T>
class SecuentialBlock : public ISerializable {
private:
	typedef std::vector<T*> RecordList;
	RecordList records;
	typename RecordList::const_iterator position;

public:

	SecuentialBlock();
	virtual ~SecuentialBlock();

	void add(const T& record);
	bool find(T& record, const IEvaluator<T>& eval);
	bool next(T& record);
	bool remove(const IEvaluator<T>& eval);
	bool remove(const T& record);
	void clear();

	virtual BigInt size() const;
	virtual void serialize(ISerializer& serializer) const;
	virtual void unserialize(IUnserializer& unserializer);
};

template<class T>
SecuentialBlock<T>::SecuentialBlock() {
	position = records.begin();
}

template<class T>
SecuentialBlock<T>::~SecuentialBlock() {
	clear();
}

template<class T>
void SecuentialBlock<T>::add(const T& record) {
	records.push_back(new T(record));
	position = records.begin();
}

template<class T>
bool SecuentialBlock<T>::find(T& record, const IEvaluator<T>& eval) {
	typename RecordList::iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		if (eval.eval(**it) == 0) {
			record = **it;
			return true;
		}
	}
	return false;
}

template<class T>
bool SecuentialBlock<T>::remove(const IEvaluator<T>& eval) {
	typename RecordList::iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		if (eval.eval(**it) == 0) {
			delete *it;
			records.erase(it);
			return true;
		}
	}
	return false;
}

template<class T>
bool SecuentialBlock<T>::remove(const T& record) {
	typename RecordList::iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		if (**it == record) {
			delete *it;
			records.erase(it);
			return true;
		}
	}
	return false;
}

template<class T>
bool SecuentialBlock<T>::next(T& record) {
	if (position == records.end())
		return false;
	record = **position;
	++position;
	return true;
}

template<class T>
void SecuentialBlock<T>::clear() {
	typename RecordList::iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		delete *it;
	}
	records.clear();
	position = records.end();
}

template<class T>
BigInt SecuentialBlock<T>::size() const {
	BigInt total = sizeof(BigInt);  // tamanio de la metadata
	T* record;
	typename RecordList::const_iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		record = *it;
		total += record->size();
	}
	return total;
}

template<class T>
void SecuentialBlock<T>::serialize(ISerializer& serializer) const {
	serializer.serializeUnsignedLongInt(records.size());
	T* record;
	typename RecordList::const_iterator it;
	for (it = records.begin(); it != records.end(); ++it) {
		record = *it;
		record->serialize(serializer);
	}
}

template<class T>
void SecuentialBlock<T>::unserialize(IUnserializer& unserializer) {
	clear();
	BigInt count = unserializer.unserializeUnsignedLongInt();
	T* record;
	for (BigInt x = 0; x < count; x++) {
		record = new T();
		record->unserialize(unserializer);
		records.push_back(record);
	}
	position = records.begin();
}

#endif /* SECUENTIALBLOCK_H_ */
